package com.sz.app.customer.api.logistics;

import com.sz.app.customer.api.logistics.dto.*;
import com.sz.biz.app.web.BaseController;
import com.sz.biz.common.base.entity.FeeType;
import com.sz.biz.common.constants.SystemConstants;
import com.sz.biz.logistics.constants.ProductGroupCode;
import com.sz.biz.logistics.core.entity.ProductGroup;
import com.sz.biz.common.customer.entity.CusUser;
import com.sz.biz.common.base.service.FeeTypeService;
import com.sz.biz.logistics.core.service.ProductGroupService;
import com.sz.biz.common.customer.service.CustomerUserService;
import com.sz.biz.logistics.core.service.ProductService;
import com.sz.common.base.dto.ResultDto;
import com.sz.common.base.utils.EntityUtils;
import com.sz.biz.logistics.billing.service.QuotationCalcService;
import com.sz.biz.logistics.billing.dto.QuotationCalcObject;
import com.sz.biz.logistics.billing.dto.QuotationCalcResult;
import com.sz.common.core.system.service.SysDictService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutionException;

/**
 * Function: 试算逻辑. <br>
 * Date: 2017年06月06日 11:38 <br>
 * Author: wentao.chang
 */
@RestController
@RequestMapping("/api/v1/calc")
@Api(description = " ", tags = "007、试算")
public class TryCalcController extends BaseController {
    @Autowired
    private QuotationCalcService quotationCalcService;
    @Autowired
    private FeeTypeService feeTypeService;
    @Autowired
    private CustomerUserService customerUserService;
    @Autowired
    private SysDictService sysDictService;
    @Autowired
    private ProductGroupService productGroupService;
    @Autowired
    private ProductService productService;

    @ApiOperation(value = "产品销售计费", notes = "-")
    @RequestMapping(value = "/sale/product", method = {RequestMethod.POST})
    public ResultDto productCalc(@RequestBody @ApiParam(value = "计费对象", required = true) ProductCalcDto dto)
            throws ExecutionException, InterruptedException {
        dto.setDomainId(SystemConstants.SystemType.CUSTOMER);//1、运营系统 2、客户系统
        PackageWeightResult pwr = handleWeightVolume(dto.getPackages());//获取要试算的 重量、体积
        int customerId = 0;
        if (dto.getCustomerId() != 0) {//取出客户对应的账户id
            CusUser cusUser = customerUserService.findById(dto.getCustomerId());
            customerId = cusUser.getRefCustomerId();
        }
        //速运多个类型
        if (!CollectionUtils.isEmpty(dto.getGroupType()) && dto.getGroupType().contains(ProductGroupCode.LAND_TRANSPORT)) {
            dto.getGroupType().add(ProductGroupCode.WAREHOSE_INTEGRATION);
            dto.getGroupType().add(ProductGroupCode.COLD_CHAIN_LOGISTICS);
            dto.getGroupType().add(ProductGroupCode.ENGINEERING_LOGISTICS);
        }
        List<TryCalcDto> dtos = new ArrayList<>();

        if (!CollectionUtils.isEmpty(dto.getMulitProductUid())) {
            for (String pUid : dto.getMulitProductUid()) {
                dto.setProductUid(pUid);
                try {
                    calcSingleProduct(customerId, dto, pwr, dtos);
                } catch (Exception e) {
                    e.printStackTrace();
                    continue;//在多产品试算时，即使有错误的，也要继续向下试算
                }
            }
        } else {
            calcSingleProduct(customerId, dto, pwr, dtos);
        }


        dtos.sort((item1, item2) ->
                (item2.getGroupName() + item2.getProductName() + item2.getTotalAmount().doubleValue())
                        .compareTo(item1.getGroupName() + item1.getProductName() + item1.getTotalAmount().doubleValue()));

        ResultDto result = new ResultDto();
        result.setMsg("计算结果");
        result.setData(dtos);
        return result;
    }

    /**
     * 计算指定产品的销售价
     *
     * @param customerId 客户id
     * @param dto        产品计算dto
     * @param pwr        生量体积
     * @param dtos
     * @throws ExecutionException
     * @throws InterruptedException
     */
    private void calcSingleProduct(int customerId, ProductCalcDto dto, PackageWeightResult pwr, List<TryCalcDto> dtos) throws ExecutionException, InterruptedException {
        QuotationCalcObject calcResult = quotationCalcService.calcProductSalePrice(customerId, dto.getGroupType(),
                dto.getProductUid(), new Date(), dto.getCargoTypeCode(), dto.getCurrencyCode(),
                pwr.getWeight(), pwr.getVolume(), dto.getWeightUnitCode(), BigDecimal.ZERO,
                dto.getFromCountry(), dto.getFromProvince(), dto.getFromCity(),
                dto.getFromArea(), dto.getFromStreet(), dto.getFromPostcode(),
                dto.getFromCountry(), dto.getFromProvince(), dto.getFromCity(),
                dto.getFromArea(), dto.getFromStreet(), dto.getFromPostcode(),
                dto.getToCountry(), dto.getToProvince(), dto.getToCity(),
                dto.getToArea(), dto.getToStreet(), dto.getToPostcode(),
                0, 0, Collections.singletonList(""), true, true,
                2);

        //组装页面的对象
        if (calcResult != null && !CollectionUtils.isEmpty(calcResult.getResult())) {
            Map<String, String> estimatedMap = sysDictService.findMapByCatalog("biz.product.estimated.unit");//产品预估时效

            List<Integer> feeTypeIds = EntityUtils.getIntPropListFromBeans(calcResult.getResult(), "feeTypeId");
            List<FeeType> feeTypes = feeTypeService.findByIds(feeTypeIds);//费用类型
            Map<String, FeeType> feeTypeMap = EntityUtils.getStringKeyMapFromBeans(feeTypes, "id");

            List<ProductGroup> pgs = productGroupService.list();//产品组
            Map<String, ProductGroup> pgMap = EntityUtils.getStringKeyMapFromBeans(pgs, "id");

            Map<String, TryCalcDto> results = new HashMap<>();
            for (QuotationCalcResult result : calcResult.getResult()) {
                //没有客户，货币与选择的货币不一致，过滤
                if (dto.getCustomerId() == 0 && !result.getCurrencyCode().equals(dto.getCurrencyCode())) {
                    continue;
                }
                //没有客户，结算方式非月结，过滤
                /*if (dto.getCustomerId() == 0 && result.getSettlementId() != 1) {
                    continue;
                }*/
                TryCalcDto tryCalcDto = results.get(result.getQuotationId() + "");
                if (tryCalcDto == null) {
                    tryCalcDto = new TryCalcDto();
                    tryCalcDto.setFeeWeight(result.getFeeWeight());
                    tryCalcDto.setFeeWeightUnitCode(result.getFeeWeightUnitCode());
                    tryCalcDto.setGroupId(result.getGroupId());
                    tryCalcDto.setProductId(result.getProductId());
                    tryCalcDto.setProductUid(result.getProductUid());
                    tryCalcDto.setProductName(result.getProductName());
                    tryCalcDto.setCurrencyCode(result.getCurrencyCode());
                    tryCalcDto.setProductEstimatedUnit(estimatedMap.get(result.getProductEstimatedUnit()));
                    tryCalcDto.setProductEstimatedTime(result.getProductEstimatedTime());
                    ProductGroup pg = pgMap.get(result.getGroupId() + "");
                    if (pg != null) {
                        tryCalcDto.setGroupName(pg.getParentId() == 1 ? "海运" : (pg.getParentId() == 6 ? "空运" : "速递"));
                    }
                    results.put(result.getQuotationId() + "", tryCalcDto);
                }
                ServiceFeeDto feeDto = new ServiceFeeDto();
                feeDto.setAmount(result.getAmount());
                feeDto.setFeeTypeId(result.getFeeTypeId());
                feeDto.setFeeTypeName(feeTypeMap.get(result.getFeeTypeId() + "").getName());
                feeDto.setServiceId(result.getServiceId());
                feeDto.setServiceUid(result.getServiceUid());
                feeDto.setCurrencyCode(result.getCurrencyCode());
                feeDto.setServiceName(result.getServiceName());
                feeDto.setServiceTypCode(result.getServiceTypCode());
                feeDto.setServiceTypCodeName(result.getServiceTypCodeName());
                if (result.isOptional()) {
                    tryCalcDto.getOptionalServices().add(feeDto);
                } else {
                    tryCalcDto.getNoneOptionalServices().add(feeDto);
                    tryCalcDto.setTotalAmount(tryCalcDto.getTotalAmount().add(feeDto.getAmount()));
                }
            }
            results.values().forEach(dtos::add);
        }
    }

    @ApiOperation(value = "订单销售费用预估", notes = "-")
    @RequestMapping(value = "/order/sale", method = {RequestMethod.POST})
    public ResultDto orderCalc(@RequestBody @ApiParam(value = "计费对象", required = true) ProductCalcDto dto)
            throws ExecutionException, InterruptedException {
        dto.setDomainId(2);
        if (dto.getCustomerId() != 0) {
            CusUser cusUser = customerUserService.findById(dto.getCustomerId());
            int customerId = cusUser.getRefCustomerId();
            dto.setCustomerId(customerId);
        }
        QuotationCalcObject calcResults = null;
        try {

            calcResults = quotationCalcService.calcProductSalePrice(
                    dto.getCustomerId(), dto.getGroupType(),
                    dto.getProductUid(), dto.getCalcDate(), dto.getCargoTypeCode(), "",
                    dto.getWeight(), BigDecimal.ZERO, dto.getUnitCode(), dto.getAnnouncePrice(),
                    dto.getFromCountry(), dto.getFromProvince(), dto.getFromCity(),
                    dto.getFromArea(), dto.getFromStreet(), dto.getFromPostcode(),
                    dto.getFetchCountry(), dto.getFetchProvince(), dto.getFetchCity(),
                    dto.getFetchArea(), dto.getFetchStreet(), dto.getFetchPostcode(),
                    dto.getToCountry(), dto.getToProvince(), dto.getToCity(),
                    dto.getToArea(), dto.getToStreet(), dto.getToPostcode(), dto.getStartPort(), dto.getEndPort(),
                    dto.getOptionServiceTypes(), false, false,
                    dto.getDomainId());
        } catch (Exception e) {
            ResultDto result = new ResultDto();
            result.setMsg("");
            Map<String, Object> map = new HashMap<>(16);
            map.put("currency", "CNY");
            map.put("amount", "-");
            result.setErrorCode(-1);
            result.setData(map);
            return result;
        }

        final BigDecimal[] amount = {BigDecimal.ZERO};
        final String[] currency = {""};
        calcResults.getResult().forEach(item -> {
            currency[0] = item.getCurrencyCode();
            if (item.isHasResult()) {
                if (!item.isOptional()) {
                    amount[0] = amount[0].add(item.getAmount());
                }
                if (item.isOptional() && dto.getOptionServiceTypes().contains(item.getServiceTypCode())) {
                    amount[0] = amount[0].add(item.getAmount());
                }
            }
        });
        Map<String, Object> map = new HashMap<>(16);
        map.put("currency", currency[0]);
        map.put("amount", amount[0]);
        ResultDto result = new ResultDto();
        result.setMsg("计算结果");
        result.setData(map);
        return result;

    }

    private PackageWeightResult handleWeightVolume(List<PackageWeightDto> packages) {
        PackageWeightResult pwr = new PackageWeightResult();

        BigDecimal weight = BigDecimal.ZERO;
        BigDecimal volume = BigDecimal.ZERO;
        for (PackageWeightDto weightDto : packages) {

            if (weightDto.getWeight() != null) {
                weight = weight.add(weightDto.getWeight());
            }
            if (weightDto.getWidth() != null && weightDto.getHeight() != null && weightDto.getLength() != null) {
                BigDecimal singleVolume = weightDto.getWidth().multiply(weightDto.getHeight()).multiply(weightDto.getLength());
                volume = volume.add(singleVolume);
            }
        }
        pwr.setWeight(weight);
        pwr.setVolume(volume);
        return pwr;
    }


}
